package com.ruoyi.repair.service.impl;

import java.util.List;
import java.util.Date;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.repair.mapper.TFaultReportMapper;
import com.ruoyi.repair.domain.TFaultReport;
import com.ruoyi.repair.service.ITFaultReportService;
import com.ruoyi.repair.service.ITWorkOrderService;
import com.ruoyi.repair.service.ITWorkPartService;
import com.ruoyi.repair.domain.TWorkOrder;
import com.ruoyi.repair.domain.TWorkPart;
 import com.ruoyi.asset.domain.TAsset;
 import com.ruoyi.asset.service.ITAssetService;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.service.IImageCleanupService;
import com.ruoyi.common.utils.SecurityUtils;
import com.alibaba.fastjson2.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;

/**
 * 故障报修Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-09-29
 */
@Service
public class TFaultReportServiceImpl implements ITFaultReportService 
{
    private static final Logger log = LoggerFactory.getLogger(TFaultReportServiceImpl.class);

    @Autowired
    private TFaultReportMapper tFaultReportMapper;

    @Autowired
    private ITWorkOrderService tWorkOrderService;

    @Autowired
    private ITWorkPartService tWorkPartService;

    @Autowired
    private ITAssetService tAssetService;

    @Autowired
    private IImageCleanupService imageCleanupService;

    /**
     * 查询故障报修
     * 
     * @param reportNo 故障报修主键
     * @return 故障报修
     */
    @Override
    public TFaultReport selectTFaultReportByReportNo(String reportNo)
    {
        return tFaultReportMapper.selectTFaultReportByReportNo(reportNo);
    }

    /**
     * 查询故障报修列表
     * 
     * @param tFaultReport 故障报修
     * @return 故障报修
     */
    @Override
    public List<TFaultReport> selectTFaultReportList(TFaultReport tFaultReport)
    {
        return tFaultReportMapper.selectTFaultReportList(tFaultReport);
    }

    /**
     * 新增故障报修
     * 
     * @param tFaultReport 故障报修
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertTFaultReport(TFaultReport tFaultReport)
    {
        // 检查设备是否已有未完成的报修
        if (StringUtils.isNotEmpty(tFaultReport.getAssetNo())) {
            if (hasUnfinishedReport(tFaultReport.getAssetNo())) {
                throw new ServiceException("该设备已有未完成的报修，不能重复添加报修");
            }
        }
        
        // 生成报修单号（保证唯一）。若前端传入且已存在，则重新生成
        if (StringUtils.isEmpty(tFaultReport.getReportNo())
                || tFaultReportMapper.selectTFaultReportByReportNo(tFaultReport.getReportNo()) != null) {
            String no;
            do {
                no = generateReportNo();
            } while (tFaultReportMapper.selectTFaultReportByReportNo(no) != null);
            tFaultReport.setReportNo(no);
        }
        
        // 设置报修时间
        if (tFaultReport.getReportTime() == null) {
            tFaultReport.setReportTime(new Date());
        }
        
        // 设置初始状态
        if (StringUtils.isEmpty(tFaultReport.getStatus())) {
            tFaultReport.setStatus("DRAFT"); // 草稿状态
        }
        
        tFaultReport.setCreateTime(DateUtils.getNowDate());
        int result = tFaultReportMapper.insertTFaultReport(tFaultReport);
        
        // 记录图片关联关系
        if (result > 0 && tFaultReport.getImageUrls() != null && !tFaultReport.getImageUrls().isEmpty()) {
            recordFaultReportImages(tFaultReport.getReportNo(), tFaultReport.getImageUrls());
        }
        
        return result;
    }

    /**
     * 修改故障报修（带乐观锁）
     * 
     * @param tFaultReport 故障报修
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateTFaultReport(TFaultReport tFaultReport)
    {
        // 获取当前故障报修信息（包含updateTime）
        TFaultReport currentReport = tFaultReportMapper.selectTFaultReportByReportNo(tFaultReport.getReportNo());
        if (currentReport == null) {
            throw new ServiceException("报修单不存在");
        }
        
        // 设置乐观锁的updateTime（用于WHERE条件检查）
        tFaultReport.setUpdateTime(currentReport.getUpdateTime());
        
        // 不设置新的updateTime，让数据库自动更新为NOW()
        int result = tFaultReportMapper.updateTFaultReport(tFaultReport);
        
        // 检查乐观锁是否生效
        if (result == 0) {
            throw new ServiceException("数据已被其他用户修改，请刷新页面后重试");
        }
        
        // 处理图片关联关系
        if (result > 0) {
            updateFaultReportImages(tFaultReport.getReportNo(), currentReport, tFaultReport);
        }
        
        return result;
    }

    /**
     * 批量删除故障报修
     * 
     * @param reportNos 需要删除的故障报修主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteTFaultReportByReportNos(String[] reportNos)
    {
        // 删除故障报修关联的图片
        for (String reportNo : reportNos) {
            try {
                imageCleanupService.deleteBusinessImages("fault_report", reportNo, "images");
                log.info("删除故障报修 {} 关联的图片", reportNo);
            } catch (Exception e) {
                log.error("删除故障报修 {} 关联的图片失败: {}", reportNo, e.getMessage());
            }
        }
        
        return tFaultReportMapper.deleteTFaultReportByReportNos(reportNos);
    }

    /**
     * 删除故障报修信息
     * 
     * @param reportNo 故障报修主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteTFaultReportByReportNo(String reportNo)
    {
        // 删除故障报修关联的图片
        try {
            imageCleanupService.deleteBusinessImages("fault_report", reportNo, "images");
            log.info("删除故障报修 {} 关联的图片", reportNo);
        } catch (Exception e) {
            log.error("删除故障报修 {} 关联的图片失败: {}", reportNo, e.getMessage());
        }
        
        return tFaultReportMapper.deleteTFaultReportByReportNo(reportNo);
    }

    /**
     * 提交故障报修（状态变为待承认，同时生成维修工单）
     * 
     * @param reportNo 报修单号
     * @return 结果
     */
    @Override
    public int submitFaultReport(String reportNo)
    {
        TFaultReport report = selectTFaultReportByReportNo(reportNo);
        if (report == null) {
            throw new ServiceException("报修单不存在");
        }

        // 更新报修单状态为待承认
        report.setStatus("PENDING_ASSIGN");
        int result = updateTFaultReport(report);

        if (result > 0) {
            // 生成维修工单
            TWorkOrder workOrder = new TWorkOrder();
            workOrder.setWorkNo(generateWorkOrderNo());
            workOrder.setRptNo(reportNo);
            workOrder.setStatusCode("PENDING_ASSIGN"); // 待指派状态
            workOrder.setIsDelete(0);
            workOrder.setCreatedAt(DateUtils.getNowDate());

            tWorkOrderService.insertTWorkOrder(workOrder);

            // 更新报修单关联维修单号
            report.setWorkOrderNo(workOrder.getWorkNo());
            updateTFaultReport(report);
        }

        return result;
    }

    /**
     * 撤回故障报修
     * 
     * @param reportNo 报修单号
     * @return 结果
     */
    @Override
    public int withdrawFaultReport(String reportNo)
    {
        TFaultReport report = selectTFaultReportByReportNo(reportNo);
        if (report == null) {
            throw new ServiceException("报修单不存在");
        }

        report.setStatus("DRAFT");
        int ret = updateTFaultReport(report);

        // 同步作废关联的维修单（标记逻辑删除），仅处理未完成工单
        try {
            TWorkOrder query = new TWorkOrder();
            query.setRptNo(reportNo);
            List<TWorkOrder> list = tWorkOrderService.selectTWorkOrderList(query);
            if (list != null) {
                for (TWorkOrder wo : list) {
                    // 仅当工单未结束时才作废
                    if (wo != null && wo.getIsDelete() != null && wo.getIsDelete() == 0) {
                        String st = wo.getStatusCode();
                        if (st == null || "PENDING_ASSIGN".equals(st) || "PENDING_EXEC".equals(st)) {
                            wo.setIsDelete(1);
                            tWorkOrderService.updateTWorkOrder(wo);
                            
                            // 同步作废关联的维修用料（标记逻辑删除）
                            try {
                                TWorkPart partQuery = new TWorkPart();
                                partQuery.setWorkNo(wo.getWorkNo());
                                List<TWorkPart> partList = tWorkPartService.selectTWorkPartList(partQuery);
                                if (partList != null) {
                                    for (TWorkPart wp : partList) {
                                        if (wp != null && wp.getIsDelete() != null && wp.getIsDelete() == 0) {
                                            wp.setIsDelete(1);
                                            tWorkPartService.updateTWorkPart(wp);
                                        }
                                    }
                                }
                            } catch (Exception ignore) {}
                        }
                    }
                }
            }
        } catch (Exception ignore) {}

        return ret;
    }

    /**
     * 承认故障报修（在维修完成后进行）
     * 
     * @param reportNo 报修单号
     * @return 结果
     */
    @Override
    public int acknowledgeFaultReport(String reportNo)
    {
        TFaultReport report = selectTFaultReportByReportNo(reportNo);
        if (report == null) {
            return 0;
        }

        // 只有在已确认状态下才能进行承认操作
        if (!"CONFIRMED".equals(report.getStatus())) {
            return 0;
        }

        // 更新报修单状态为已承认
        report.setStatus("ACKNOWLEDGED");
        int result = updateTFaultReport(report);

        if (result > 0) {
            // 更新关联的资产状态为正常
            updateAssetStatusToNormal(report);
        }

        return result;
    }

    /**
     * 拒绝承认故障报修（在维修完成后进行）
     * 
     * @param reportNo 报修单号
     * @return 结果
     */
    @Override
    public int rejectFaultReport(String reportNo)
    {
        log.info("开始拒绝承认报修单: {}", reportNo);
        
        TFaultReport report = selectTFaultReportByReportNo(reportNo);
        if (report == null) {
            log.error("报修单不存在: {}", reportNo);
            return 0;
        }

        log.info("当前报修单状态: {}", report.getStatus());
        
        // 只有在已确认状态下才能进行拒绝承认操作
        if (!"CONFIRMED".equals(report.getStatus())) {
            log.error("报修单状态不是已确认，无法拒绝承认: {}", report.getStatus());
            return 0;
        }

        try {
            report.setStatus("PENDING_ASSIGN");
            log.info("更新报修单状态为待指派");
            int result = updateTFaultReport(report);
            log.info("更新报修单结果: {}", result);

            if (result > 0) {
                // 生成新的维修工单
                TWorkOrder workOrder = new TWorkOrder();
                workOrder.setWorkNo(generateWorkOrderNo());
                workOrder.setRptNo(reportNo);
                workOrder.setStatusCode("PENDING_ASSIGN"); // 待指派状态
                workOrder.setIsDelete(0);
                workOrder.setCreatedAt(DateUtils.getNowDate());

                log.info("创建维修工单: {}", workOrder.getWorkNo());
                tWorkOrderService.insertTWorkOrder(workOrder);

                // 更新报修单关联新的维修单号
                report.setWorkOrderNo(workOrder.getWorkNo());
                log.info("更新报修单关联维修单号");
                updateTFaultReport(report);
                
                // 更新关联的资产状态为故障(ASSET_STATUS_002)
                updateAssetStatusToFault(report);
            }

            log.info("拒绝承认操作完成，结果: {}", result);
            return result;
        } catch (Exception e) {
            log.error("拒绝承认操作失败: {}", e.getMessage(), e);
            throw new ServiceException("拒绝承认失败: " + e.getMessage());
        }
    }

    /**
     * 更新故障报修状态（带乐观锁）
     * 
     * @param reportNo 报修单号
     * @param status 新状态
     * @return 结果
     */
    @Override
    public int updateFaultReportStatus(String reportNo, String status)
    {
        TFaultReport report = selectTFaultReportByReportNo(reportNo);
        if (report == null) {
            throw new ServiceException("报修单不存在");
        }

        report.setStatus(status);
        // 不设置updateTime，让updateTFaultReport方法处理乐观锁
        return updateTFaultReport(report);
    }

    /**
     * 获取状态履历
     * 
     * @param reportNo 报修单号
     * @return 状态履历列表
     */
    @Override
    public List<Object> getStatusHistory(String reportNo)
    {
        List<Object> history = new ArrayList<>();
        
        // 模拟状态履历数据
        Map<String, Object> record1 = new HashMap<>();
        record1.put("time", "2021-03-23 14:23:42");
        record1.put("operator", "晏波新");
        record1.put("operation", "创建报修单");
        history.add(record1);

        Map<String, Object> record2 = new HashMap<>();
        record2.put("time", "2021-03-23 14:25:15");
        record2.put("operator", "晏波新");
        record2.put("operation", "提交报修单");
        history.add(record2);

        return history;
    }

    /**
     * 生成报修单号
     */
    private String generateReportNo()
    {
        return "BX-" + System.currentTimeMillis();
    }

    /**
     * 生成维修单号
     */
    private String generateWorkOrderNo()
    {
        return "WX-" + System.currentTimeMillis();
    }

    /**
     * 更新资产状态为正常
     * 
     * @param faultReport 故障报修
     */
    private void updateAssetStatusToNormal(TFaultReport faultReport) {
        try {
            if (faultReport.getAssetNo() != null) {
                // 获取资产信息
                TAsset asset = tAssetService.selectTAssetByAssetNo(faultReport.getAssetNo());
                if (asset != null) {
                    // 更新资产状态为正常 (ASSET_STATUS_001)
                    asset.setStatusCode("ASSET_STATUS_001");
                    tAssetService.updateTAsset(asset);
                    log.info("资产 {} 状态已更新为正常", faultReport.getAssetNo());
                }
            }
        } catch (Exception e) {
            log.error("更新资产状态为正常失败: {}", e.getMessage(), e);
            throw new ServiceException("更新资产状态失败: " + e.getMessage());
        }
    }
    
    /**
     * 更新资产状态为故障
     * 
     * @param faultReport 故障报修
     */
    private void updateAssetStatusToFault(TFaultReport faultReport) {
//        // 暂时注释掉资产状态更新功能，避免依赖问题
//        log.info("资产状态更新功能暂时禁用: {}", faultReport.getAssetNo());

        try {
            if (faultReport.getAssetNo() != null) {
                // 获取资产信息
                TAsset asset = tAssetService.selectTAssetByAssetNo(faultReport.getAssetNo());
                if (asset != null) {
                    // 更新资产状态为故障 (ASSET_STATUS_002)
                    asset.setStatusCode("ASSET_STATUS_002");
                    tAssetService.updateTAsset(asset);
                }
            }
        } catch (Exception e) {
            log.error("更新资产状态为故障失败: {}", e.getMessage(), e);
            throw new ServiceException("更新资产状态失败: " + e.getMessage());
        }

    }

    /**
     * 记录故障报修图片关联关系
     */
    private void recordFaultReportImages(String reportNo, String imageUrlsJson) {
        try {
            List<String> imageUrls = JSON.parseArray(imageUrlsJson, String.class);
            Long userId = SecurityUtils.getUserId();
            
            for (String imageUrl : imageUrls) {
                if (imageUrl != null && !imageUrl.isEmpty()) {
                    // 从URL中提取文件名
                    String fileName = extractFileNameFromUrl(imageUrl);
                    if (fileName != null) {
                        imageCleanupService.recordImageAttachment(
                            fileName, "fault_report", reportNo, "images", userId
                        );
                        log.info("记录故障报修图片关联: {} -> {}", fileName, reportNo);
                    }
                }
            }
        } catch (Exception e) {
            log.error("记录故障报修图片关联失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 更新故障报修图片关联关系
     */
    private void updateFaultReportImages(String reportNo, TFaultReport oldReport, TFaultReport newReport) {
        try {
            String oldImageUrls = oldReport != null ? oldReport.getImageUrls() : null;
            String newImageUrls = newReport.getImageUrls();
            
            // 如果图片没有变化，直接返回
            if (oldImageUrls != null && oldImageUrls.equals(newImageUrls)) {
                return;
            }
            
            Long userId = SecurityUtils.getUserId();
            
            // 处理旧图片
            if (oldImageUrls != null && !oldImageUrls.isEmpty()) {
                List<String> oldUrls = JSON.parseArray(oldImageUrls, String.class);
                for (String oldUrl : oldUrls) {
                    if (oldUrl != null && !oldUrl.isEmpty()) {
                        String oldFileName = extractFileNameFromUrl(oldUrl);
                        if (oldFileName != null) {
                            imageCleanupService.updateImageAttachment(
                                oldFileName, null, "fault_report", reportNo, "images", userId
                            );
                        }
                    }
                }
            }
            
            // 处理新图片
            if (newImageUrls != null && !newImageUrls.isEmpty()) {
                recordFaultReportImages(reportNo, newImageUrls);
            }
            
        } catch (Exception e) {
            log.error("更新故障报修图片关联失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 从URL中提取文件名
     */
    private String extractFileNameFromUrl(String url) {
        if (url == null || url.isEmpty()) {
            return null;
        }
        
        try {
            // 如果是完整的URL，提取文件名部分
            if (url.contains("/")) {
                return url.substring(url.lastIndexOf("/") + 1);
            }
            // 如果直接是文件名，直接返回
            return url;
        } catch (Exception e) {
            log.error("提取文件名失败: {}", url, e);
            return null;
        }
    }

    /**
     * 检查设备是否有未完成的报修
     * 
     * @param assetNo 设备编号
     * @return 是否有未完成报修
     */
    @Override
    public boolean hasUnfinishedReport(String assetNo) {
        if (StringUtils.isEmpty(assetNo)) {
            return false;
        }
        int count = tFaultReportMapper.countUnfinishedReportsByAssetNo(assetNo);
        return count > 0;
    }
}
